package com.example.demo.controller;

import cn.hutool.core.date.DateUtil;
import com.example.demo.Util.ConcurrentUtil;
import com.example.demo.service.ExecutorTaskService;
import lombok.SneakyThrows;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

@RestController
@RequestMapping("/api")
public class TaskThread {

    /**
     * 多线程
     */
    @GetMapping("/task")
    public void task() {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        ConcurrentUtil.doJob(executorService, this::taskA);
        ConcurrentUtil.doJob(executorService, this::taskB);
        ConcurrentUtil.doJob(executorService, this::taskC);
        ConcurrentUtil.doJob(executorService, new ExecutorTaskService().taskRun());
        ConcurrentUtil.doJob(executorService, new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(300);
            }
        });
        executorService.shutdown();
    }

    /**
     * 多线程 call
     */
    @GetMapping("/call")
    public Boolean tasKCall() throws ExecutionException, InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        ExecutorTaskService service = new ExecutorTaskService();
        List<Callable> methods = new ArrayList<>();
        methods.add(service.taskCallA());
        methods.add(service.taskCallB());
        methods.add(service.taskCallC());
        Boolean str = null;
        for (Callable method : methods) {
            str = (Boolean) ConcurrentUtil.doJobCall(executorService, method).get();
        }
        executorService.shutdown();
        return str;
    }

    /**
     * 多线程 call
     */
    @GetMapping("/calls")
    public Map<Integer, Boolean> tasKCalls() {
        ExecutorService executorService = new ThreadPoolExecutor(10, 10, 60L,
                TimeUnit.SECONDS, new LinkedBlockingQueue<>(8));

        Map<Integer, Boolean> map = new HashMap<>();
        for (int i = 0; i < 5; i++) {
            int finalI = i;
            executorService.execute(new Runnable() {
                @SneakyThrows
                @Override
                public void run() {
                    int num = (int) Math.ceil(Math.random() * 10);
                    Thread.sleep(num * 1000);
                    System.out.println(finalI);
                    map.put(num, method(num));
                }
            });
        }
        System.out.println(2323);
        executorService.shutdown();
        try {
            executorService.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * CountDownLatch
     * 用来控制一个或者多个线程等待多个线程。
     * @return
     * @throws InterruptedException
     */
    @GetMapping("/countdownLatch")
    public Map<Integer, Boolean> countdownLatch() throws InterruptedException {
        final int totalThread = 10;
        CountDownLatch countDownLatch = new CountDownLatch(totalThread);
        ExecutorService executorService = Executors.newCachedThreadPool();
        Map<Integer, Boolean> map = new HashMap<>();
        for (int i = 0; i < totalThread; i++) {
            int finalI = i;
            executorService.execute(() -> {
                int num = (int) Math.ceil(Math.random() * 10);
                System.out.println(finalI);
                map.put(num, method(num));
                countDownLatch.countDown();
            });
        }
        countDownLatch.await();
        System.out.println("end");
        executorService.shutdown();
        return map;
    }


    /**
     * 普通
     */
    @GetMapping("/callu")
    public List<Boolean> tasKCallu() throws InterruptedException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        List<Boolean> list = new ArrayList<>();
        StopWatch watch = new StopWatch();
        for (int i = 0; i < 5; i++) {
            int num = (int) Math.ceil(Math.random() * 10);
            watch.start("第" + i + "次");
            Thread.sleep(num * 100);
            watch.stop();
            System.out.println(i);
            list.add(method(num));
        }
        System.out.println(watch.prettyPrint());
        executorService.shutdown();
        return list;
    }

    private Boolean method(int random) {
        return  random > 5;
    }

    public void taskA() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("do task a");
    }


    public void taskB() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("do task b");
    }

    private final static AtomicInteger taskCTryTimes = new AtomicInteger(1);

    public void taskC() {
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        if (taskCTryTimes.getAndIncrement() < 3) {
            System.out.println("do task c fail");
            throw new RuntimeException("taskC fail");
        }
        System.out.println("do task c");
    }
}
